#pragma once

#include "Socket.hpp"
#include "TCPServe.hpp"
#include "Util.hpp"
#include <unordered_map>
#include <sstream>
using namespace SocketModule;

const std::string Gspace = " ";
const std::string GLineSpace = "\r\n";
const std::string webroot = "./webroot";
const std::string homepage = "index.html";
const std::string page_404 = "page404.html";
const std::string Glinesep = ": ";

class HttpRequest
{
public:
    HttpRequest() {}
    std::string Serialization()
    {
    }
    void ParseLine(std::string &GetRequestLine)
    {
        std::stringstream ss(GetRequestLine);
        ss >> HttpRequestMethod >> URL >> HttpVersion;
    }
    bool DeSerialization(std::string &Content)
    {
        // 提取请求行
        std::string GetRequestLine;
        bool n = Util::ReadOneLineFromFile(Content, &GetRequestLine, GLineSpace);
        if (!n)
            return false;
        LOG(INFO) << "请求行是 " << GetRequestLine;

        // 对请求行的数据进行反序列化
        ParseLine(GetRequestLine);

        if (URL == "/")
            URL = webroot + URL + homepage;
        else
            URL = webroot + URL;

        LOG(DEBUG) << "HttpRequestMethod:" << HttpRequestMethod;
        LOG(DEBUG) << "URL:" << URL;
        LOG(DEBUG) << "HttpVersion:" << HttpVersion;

        return true;
    }

    std::string GetURL() { return URL; }
    ~HttpRequest() {}

private:
    std::string HttpRequestMethod;
    std::string URL;
    std::string HttpVersion;

    std::unordered_map<std::string, std::string> HttpRequestHead;
    std::string BackLine;
    std::string HttpRequestContent;
};

class HttpResponse
{
public:
    HttpResponse() : BlankLine(GLineSpace)
    {
    }
    std::string Serialization()
    {
        std::string statusLine = HttpVersion +
                                 Gspace +
                                 std::to_string(StatusCode) +
                                 Gspace +
                                 StatusCodeDesc +
                                 GLineSpace;
        std::string resp_header;
        for (auto &head : HttpResponseHead)
        {
            std::string line = head.first + Glinesep + head.second + GLineSpace;
            resp_header += line;
        }
        return statusLine + resp_header + BlankLine + HttpResponseContent;
    }
    void SetResponseContent(const std::string &key, const std::string &value)
    {
        auto it = HttpResponseHead.find(key);
        if (it != HttpResponseHead.end())
            it->second = value; // 更新现有值
        else
            HttpResponseHead.insert(std::make_pair(key, value)); // 插入新值
    }
    // void SetResponseContent(const std::string &key,const std::string &value)
    // {
    //     auto it=HttpResponseHead.find(key);
    //     if(it!=HttpResponseHead.end())
    //         return ;
    //     HttpResponseHead.insert(std::make_pair(key,value));
    // }

    void SetStatusCodeAndCodeDesc(int code)
    {
        StatusCode = code;
        switch (code)
        {
        case 404:
            StatusCodeDesc = "Not Found";
            break;

        case 200:
            StatusCodeDesc = "OK";
            break;

        default:
            break;
        }
    }

    bool MakeResponse()
    {
        // 设置必要的响应头
        HttpVersion = "HTTP/1.1"; // 一定要设置，如果检查其他函数没问题，就检查响应头

        if (TargetFile == "./webroot/favicon.ico")
        {
            LOG(INFO) << "用户请求 " << TargetFile << " 忽略它";
            return false;
        }
        bool res = Util::ReadFileContent(TargetFile, &HttpResponseContent);
        // LOG(DEBUG) << "=========" << HttpResponseContent << "=========";
        // 这里没有重复打开过文件，我们认为这个文件是不存在的
        if (!res)
        {
            // HttpResponseContent = "";
            LOG(WARNING) << "client want to request " << TargetFile << " but not found";
            SetStatusCodeAndCodeDesc(404);
            TargetFile = webroot + "/"+page_404;
            int filesize = Util::GetContentLen(TargetFile);
            bool n=Util::ReadFileContent(TargetFile,&HttpResponseContent);
            if(!n)
            {
                HttpResponseContent = "<html><body><h1>404 Not Found</h1></body></html>";
            }
            std::string Suffix = URLtoContentTypeSuffix(TargetFile);
            SetResponseContent("Content-Type", Suffix);
            SetResponseContent("Content-Length", std::to_string(filesize));
        }
        else
        {
            LOG(DEBUG) << "用户请求了" << TargetFile;
            // LOG(DEBUG)<<"====="<<TargetFile<<"=========";

            SetStatusCodeAndCodeDesc(200);
            std::string Suffix = URLtoContentTypeSuffix(TargetFile);
            LOG(DEBUG) << "=========" << Suffix << "=========";

            int filesize = Util::GetContentLen(TargetFile);
            LOG(DEBUG) << "=========" << filesize << "=========";

            SetResponseContent("Content-Type", Suffix);
            SetResponseContent("Content-Length", std::to_string(filesize));
        }

        return true;//这里全部返回true，即使访问页面不存在，也要发送数据，否则浏览器拿不到数据
    }
    // 传过来的参数是一个类似/a/b/c.html类似的字符串，需要将其后缀变成浏览器可以识别的后缀
    std::string URLtoContentTypeSuffix(std::string &targetfile)
    {
        int pos = targetfile.rfind(".");
        // 默认解析为html文件
        if (pos == std::string::npos)
            return "text/html";
        std::string suffix = targetfile.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".png")
            return "image/png";
        else
            return "";
    }

    bool DeSerialization(std::string Content)
    {
    }
    void SetTargetFile(const std::string &targetfile) { TargetFile = targetfile; }

    ~HttpResponse() {}
    // private:
    std::string HttpVersion;
    int StatusCode;
    std::string StatusCodeDesc;

    std::unordered_map<std::string, std::string> HttpResponseHead;
    std::string BlankLine;
    std::string HttpResponseContent;

    std::string TargetFile;
};

// 基于TCP/IP协议，所以使用TCPServe
class Http
{
public:
    Http(uint16_t port)
        : HttpServe(std::make_unique<TCPServe>(port))
    {
    }
    void HttpRequestHandle(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        std::string HttpRequestString;
        int n = sock->Recv(&HttpRequestString);
        // std::cout<<HttpRequestString<<std::endl;
        // 还需要添加的功能
        // 1.图片等资源是以二进制（字节流）形式传输的，需要重写读取文件的逻辑
        // 2.处理访问不存在的页面，处理跳转逻辑
        // 3.content-length 哈希表映射，处理内容和长度，查找子串，然后截断处理
        // 4.content-type html,jpg,png等后缀的文件内容的格式
        //
        if (n > 0)
        {
            HttpRequest Hresq;
            Hresq.DeSerialization(HttpRequestString);
            // std::cout<<HttpRequestString<<std::endl;
            HttpResponse Hresp;
            Hresp.SetTargetFile(Hresq.GetURL());
            if (Hresp.MakeResponse())
            {
                std::string resp_str = Hresp.Serialization();
                sock->Send(resp_str);
            }
        }
#ifdef DEBUG
        // #define DEBUG
        std::string HttpRequestString;
        sock->Recv(&HttpRequestString);
        std::cout << HttpRequestString << std::endl;

        HttpResponse resp;
        resp.HttpVersion = "HTTP/1.1";
        resp.StatusCode = 200;
        resp.StatusCodeDesc = "OK";

        std::string filename = webroot + homepage;
        bool res = Util::ReadFileContent(filename, &(resp.HttpResponseContent));
        (void)res;
        std::string response_str = resp.Serialization();
        sock->Send(response_str);
#endif
    }
    void Start()
    {
        HttpServe->Start([this](std::shared_ptr<Socket> &sock, InetAddr &client)
                         { this->HttpRequestHandle(sock, client); });
    }
    ~Http() {}

private:
    std::unique_ptr<TCPServe> HttpServe;
};
